<template>
    <el-container class="_fc-designer" :style="'height:' + dragHeight">
        <el-aside>
            <el-container>
                <el-header>
                    <div>
                        <h2>表单设计器</h2>
                    </div>
                    <div style="line-height: 150%">
                        <el-row style="justify-content: center; cursor: pointer" v-if="model.length != 0">
                            <el-dropdown trigger="click" @command="changeModel">
                                <el-button style="color: #000" type="text" @click="modelItem != null ? (visible.model = true) : ''">
                                    <el-row>
                                        <el-col :span="24"><i class="jd-icon icon-data-model" style="font-size: 22px"></i></el-col>
                                        <el-col :span="24" style="padding-top: 5px">
                                            <div v-if="modelItem == null">数据模型</div>
                                            <div v-else>{{ modelItem.tableComment }}</div>
                                        </el-col>
                                    </el-row>
                                </el-button>
                                <template #dropdown>
                                    <el-dropdown-menu>
                                        <el-dropdown-item icon="el-icon-suitcase" v-for="(item, index) in model" :key="index" :command="beforeCommand(item)">{{ item.tableComment }}</el-dropdown-item>
                                    </el-dropdown-menu>
                                </template>
                            </el-dropdown>
                        </el-row>
                    </div>
                </el-header>
                <el-main class="nopadding">
                    <template v-for="(item, index) in menuList" :key="index" v-if="visible.layout == 'control'">
                        <div class="_fc-l-group">
                            <div class="_fc-l-title">{{ item.title }}</div>
                            <div class="_fc-l-content">
                                <draggable :group="{ name: 'default', pull: 'clone', put: false }" :sort="false" itemKey="name" :list="item.list">
                                    <template #item="{ element }">
                                        <div class="_fc-l-item" @click="addDrag(element)">
                                            <div class="_fc-l-icon">
                                                <i class="jd-icon" :class="element.icon || 'icon-input'"></i>
                                            </div>
                                            <span class="_fc-l-name">{{ t('components.' + element.name + '.name') || element.label }}</span>
                                        </div>
                                    </template>
                                </draggable>
                            </div>
                        </div>
                    </template>
                    <template v-else-if="visible.layout == 'model'">
                        <div class="_fc-l-group">
                            <div class="_fc-l-title">
                                数据模型
                                <div style="float: right; cursor: pointer" @click="visible.layout = 'control'">[关闭<i class="jd-icon icon-close" style="font-size: 14px"></i>]</div>
                            </div>
                            <div class="_fc-l-content">
                                <draggable :group="{ name: 'default', pull: 'clone', put: false }" :sort="false" itemKey="name" :list="tableFields">
                                    <template #item="{ element }">
                                        <div class="_fc-l-item" @click="addDrag(element)">
                                            <div class="dataBind" v-if="element.dataBind">
                                                <i class="jd-icon icon-check" style="font-size: 15px; font-weight: bolder"></i>
                                            </div>
                                            <div class="_fc-l-icon">
                                                <i class="jd-icon" :class="element.icon || 'icon-input'"></i>
                                            </div>
                                            <div class="_fc-l-name">
                                                {{ element.label }}<br />
                                                <span class="_fc-l-remark">{{ element.field }}</span>
                                            </div>
                                        </div>
                                    </template>
                                </draggable>
                            </div>
                        </div>
                    </template>
                    <template v-else-if="visible.layout == 'modelbind'">
                        <div class="_fc-l-group">
                            <div class="_fc-l-title">
                                模型绑定
                                <div style="float: right; cursor: pointer" @click="visible.layout = 'control'">[关闭<i class="jd-icon icon-close" style="font-size: 14px"></i>]</div>
                            </div>
                            <div class="model_wrap" v-if="modelTree.length != 0">
                                <el-tree
                                    :data="modelTree"
                                    ref="tree"
                                    show-checkbox
                                    check-on-click-node
                                    default-expand-all
                                    :check-strictly="true"
                                    node-key="treeId"
                                    :default-checked-keys="modelId"
                                    @check="(data, node) => modelCheck(data, node, this)"
                                    @check-change="(data, checked) => modelCheckedChange(data, checked, this)"
                                >
                                    <template #default="{ node, data }">
                                        <span class="custom-tree-node">
                                            <span class="label" v-if="data.field != null">{{ data.label }}({{ data.field }})</span>
                                            <span class="label" v-else>{{ data.label }}</span>
                                        </span>
                                    </template>
                                </el-tree>
                            </div>
                            <div class="model_wrap" v-else>
                                <el-empty description="暂无数据模型信息" :image-size="100" style="margin-top: 200px"></el-empty>
                            </div>
                        </div>
                    </template>
                </el-main>
            </el-container>
        </el-aside>
        <el-container>
            <el-header>
                <el-row>
                    <h2>{{ appInfo.appName }}</h2>
                </el-row>
                <el-row>
                    <el-radio-group v-model="form.value.form.formMode">
                        <el-radio-button label="电脑端(PC)" size="medium"></el-radio-button>
                        <el-radio-button label="移动端(H5)" size="medium"></el-radio-button>
                    </el-radio-group>
                </el-row>
                <el-row>
                    <el-dropdown trigger="click" @command="changeForm" v-if="forms != null && forms.length > 0">
                        <el-button text>
                            <div v-if="processItem == null">
                                切换表单<el-icon class="el-icon--right"><el-icon-arrow-down /></el-icon>
                            </div>
                            <div v-else>
                                {{ processItem.formName }}<el-icon class="el-icon--right"><el-icon-arrow-down /></el-icon>
                            </div>
                        </el-button>
                        <template #dropdown>
                            <el-dropdown-menu>
                                <el-dropdown-item :icon="item.formType == 1 ? 'el-icon-document' : 'el-icon-checked'" v-for="(item, index) in forms" :key="index" :command="beforeCommand(item)">
                                    {{ item.formName }}
                                    <span v-if="item.processId != null">(<i class="jd-icon icon-process" style="font-size: 15px; margin-left: 5px"></i>)</span>
                                </el-dropdown-item>
                                <el-dropdown-item icon="el-icon-document-add" :command="beforeCommand('create')" divided> 新建表单 </el-dropdown-item>
                            </el-dropdown-menu>
                        </template>
                    </el-dropdown>
                </el-row>
            </el-header>
            <el-main style="padding: 20px">
                <div class="_fc-m-drag">
                    <div v-if="form.value.form.formMode == '移动端(H5)'" class="_fc-m-drag_wap_header"></div>
                    <div ref="mianscroll" class="_fc-m-drag" :class="form.value.form.formMode == '移动端(H5)' ? '_fc-m-drag_wap' : ''" @contextmenu.prevent="openMenu">
                        <DragForm :rule="dragForm.rule" :option="form.value" v-model:api="dragForm.api"></DragForm>
                        <div class="empty" v-if="dragForm.rule[0].children.length == 0">
                            <el-empty description="从左侧拖入或点击添加组件" :image-size="100"></el-empty>
                        </div>
                    </div>
                    <div v-if="form.value.form.formMode == '移动端(H5)'" class="_fc-m-drag_wap_footer"></div>
                </div>
                <!-- 右键菜单 -->
                <jd-contextmenu ref="contextmenu" @command="handleCommand">
                    <jd-contextmenu-item icon="el-icon-edit" command="saveForm" title="表单保存" suffix="Ctrl+S"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-box" command="a" title="另存为模板"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-refresh" command="refresh" title="页面刷新" suffix="Ctrl+R"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-position" command="previewFc" title="效果预览" :disabled="dragForm.rule[0].children.length == 0"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-suitcase" command="d" title="从数据模型导入" divided></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-goods-filled" command="d" title="从第三方库导入" suffix="Store" divided></jd-contextmenu-item>
                    <jd-contextmenu-item command="d" title="从模板库中导入" suffix="Form"></jd-contextmenu-item>
                    <jd-contextmenu-item command="d" title="从文件中导入" suffix="Excel"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-connection" command="formScript" title="表单脚本" divided suffix="Script"></jd-contextmenu-item>
                    <jd-contextmenu-item icon="el-icon-setting" command="formConfig" title="表单属性" suffix="Config"></jd-contextmenu-item>
                </jd-contextmenu>
            </el-main>
        </el-container>
        <el-aside class="_fc-r">
            <el-container>
                <el-header style="justify-content: right">
                    <el-button type="info" icon="el-icon-promotion" @click="previewFc" :disabled="dragForm.rule[0].children.length == 0">{{ t('designer.preview') }}</el-button>
                    <el-button type="danger" icon="el-icon-edit" @click="saveForm" :disabled="dragForm.rule[0].children.length == 0">保 存</el-button>
                    <el-dropdown trigger="click" @command="formSetting">
                        <el-button type="primary">
                            更 多<el-icon class="el-icon--right"><el-icon-arrow-down /></el-icon>
                        </el-button>
                        <template #dropdown>
                            <el-dropdown-menu>
                                <el-dropdown-item icon="el-icon-setting" command="formConfig">表单属性</el-dropdown-item>
                                <el-dropdown-item icon="el-icon-connection" command="formScript">表单脚本</el-dropdown-item>
                                <el-dropdown-item icon="el-icon-school" command="formVariable">系统变量</el-dropdown-item>
                                <el-dropdown-item icon="el-icon-document-copy" command="clone" :disabled="form.value.form.formId == ''">克隆表单</el-dropdown-item>
                                <el-dropdown-item icon="el-icon-delete" divided command="delete" :disabled="form.value.form.formId == ''">删除表单</el-dropdown-item>
                            </el-dropdown-menu>
                        </template>
                    </el-dropdown>
                </el-header>
                <el-main class="nopadding">
                    <el-card v-if="activeTab === 'form'" shadow="never" class="_fc_card">
                        <template #header>
                            {{ t('designer.config.form') }}
                        </template>
                        <DragForm :rule="form.rule" :option="form.option" v-model="form.value.form" v-model:api="form.api"></DragForm>
                    </el-card>
                    <el-card v-if="activeTab === 'props'" :key="activeRule ? activeRule._id : ''" shadow="never" class="_fc_card">
                        <template #header>
                            {{ t('designer.config.component') }}
                        </template>
                        <DragForm v-show="showBaseRule" v-model:api="baseForm.api" :rule="baseForm.rule" :option="baseForm.options" @change="baseChange"></DragForm>
                        <DragForm v-model:api="propsForm.api" :rule="propsForm.rule" :option="propsForm.options" @change="propChange" @removeField="propRemoveField"></DragForm>
                        <DragForm v-show="showValidate" v-model:api="validateForm.api" :rule="validateForm.rule" :option="validateForm.options" @update:modelValue="validateChange"></DragForm>
                    </el-card>
                </el-main>
                <!--el-footer>
                    <el-row style="font-size: 14px;padding-top: 10px;justify-content: center;">
                        配置文件 2023-03-19 09:41:12 自动保存
                    </el-row>
                </el-footer-->
            </el-container>
            <el-dialog v-model="preview.state" fullscreen append-to-body>
                <div v-if="form.value.form.formMode == '移动端(H5)'" class="_fc-m-drag_wap_header" style="top: unset"></div>
                <el-scrollbar :style="form.value.form.formMode == '移动端(H5)' ? 'height:calc(100vh - 250px);' : 'height:calc(100vh - 130px);'">
                    <div class="_fc-m-drag" :class="form.value.form.formMode == '移动端(H5)' ? '_fc-m-drag_wap' : ''">
                        <ViewForm :rule="preview.rule" :option="preview.option" v-model:api="preview.api" v-if="preview.state"></ViewForm>
                        <div class="empty" v-if="dragForm.rule[0].children.length == 0">
                            <el-empty description="从左侧拖入或点击添加组件" :image-size="100"></el-empty>
                        </div>
                    </div>
                </el-scrollbar>
                <div v-if="form.value.form.formMode == '移动端(H5)'" class="_fc-m-drag_wap_footer" style="bottom: unset"></div>
            </el-dialog>
        </el-aside>
    </el-container>

    <form-script v-if="visible.script" ref="scriptDialog" :script="form.value" :variables="Variables" @success="saveFormScript" @closed="visible.script = false"></form-script>
    <form-variable v-if="visible.variable" ref="variableDialog" :variables="Variables" @closed="visible.variable = false"></form-variable>
</template>

<script>
import { ElNotification, ElMessageBox, ElMessage } from 'element-plus';
import form from '../config/base/form';
import field from '../config/base/field';
import validate from '../config/base/validate';
import { deepCopy } from '@form-create/utils/lib/deepextend';
import is, { hasProperty } from '@form-create/utils/lib/type';
import { lower } from '@form-create/utils/lib/tocase';
import { ruleList, convertList } from '../config/rule';
import draggable from 'vuedraggable/src/vuedraggable';
import createMenu from '../config/menu';
import { upper, useLocale } from '../utils/index';
import { designerForm } from '../utils/form';
import viewForm from '../utils/form';
import PinYin from 'js-pinyin';
import sysConfig from '@/config';
import tool from '@/utils/tool';
import API from '../../../api/index';
import { computed, reactive, toRefs, ref, getCurrentInstance, provide, nextTick, watch, defineComponent, unref } from 'vue';
import jdContextmenu from '@/components/jdContextmenu';
import jdContextmenuItem from '@/components/jdContextmenu/item';
import FormScript from './FormScript.vue';
import FormVariable from './FormVariable.vue';

export default defineComponent({
    name: 'FcDesigner',
    components: {
        draggable,
        DragForm: designerForm.$form(),
        ViewForm: viewForm.$form(),
        jdContextmenu,
        jdContextmenuItem,
        FormScript,
        FormVariable
    },
    props: ['menu', 'height', 'config', 'mask', 'locale', 'appInfo', 'model', 'modelTree', 'forms'],
    setup(props) {
        const { menu, height, config, mask, locale } = toRefs(props);
        const vm = getCurrentInstance();
        provide('fcx', ref({ active: null }));
        provide('designer', vm);

        const dragHeight = computed(() => {
            const h = height.value;
            if (!h) return '100%';
            return is.Number(h) ? `${h}px` : h;
        });
        const t = useLocale(locale).t;
        const data = reactive({
            $API: API,
            cacheProps: {},
            moveRule: null,
            addRule: null,
            added: null,
            activeTab: 'form',
            activeRule: null,
            modelId: [],
            children: ref([]),
            menuList: menu.value || createMenu({ t }),
            modelItem: null,
            tableFields: null,
            processForms: null,
            processItem: null,
            showBaseRule: false,
            showValidate: false,
            visible: {
                preview: false,
                layout: 'control',
                model: false,
                script: false,
                variable: false
            },
            preview: {
                state: false,
                rule: [],
                option: {}
            },
            dragForm: ref({
                rule: [],
                api: {}
            }),
            form: {
                rule: form({ t }),
                api: {},
                option: {
                    form: {
                        labelPosition: 'top',
                        size: 'default'
                    },
                    submitBtn: false
                },
                value: {
                    form: {
                        inline: false,
                        hideRequiredAsterisk: false,
                        labelPosition: 'right',
                        size: 'default',
                        labelWidth: '100px',
                        formCreateSubmitBtn: true,
                        formCreateResetBtn: false,
                        formScript: '',
                        formMode: '电脑端(PC)'
                    },
                    // 表单创建成功后回调函数
                    mounted: function (jPortal) {
                        //设置字段值
                        //jPortal.form.DHWB = new Date().getTime();
                        //jPortal.setValue({DHWB:'Hello'})
                        //console.log('表单创建成功后回调函数,jPortal',jPortal);
                    },
                    // 表单重载后回调函数
                    // onReload:function(jPortal){
                    //     console.log('表单重载后回调函数,jPortal',jPortal);
                    // },
                    // 表单提交回调函数
                    onSubmit: function (formData, jPortal) {
                        console.log('formData', JSON.stringify(formData));
                        console.log('jPortal', jPortal);
                    },
                    // 设置表单初始值
                    //formData: {DHWB: 'field1'},
                    // 表单创建成功后回调函数
                    // mounted: function(jPortal){
                    //     jPortal.form.DHWB = new Date().getTime();
                    //     //设置字段值
                    //     //jPortal.setValue({DHWB:'Hello'})
                    //     console.log('表单创建成功后回调函数,jPortal',jPortal);
                    // },
                    // 表单重载后回调函数
                    // onReload:function(jPortal){
                    //     console.log('表单重载后回调函数,jPortal',jPortal);
                    // },
                    // 表单提交回调函数
                    // onSubmit:function(formData, jPortal){
                    //     console.log('formData',JSON.stringify(formData));
                    //     console.log('jPortal',jPortal);
                    //     console.log(jPortal.form.DHWB);
                    //     // 重置表单字段值
                    //     jPortal.resetFields();
                    //     jPortal.disabled(true, 'DHWB')

                    //     // 重写执行函数
                    //     // jPortal.onSubmit((formData, jPortal)=>{
                    //     //     console.log("jPortal",jPortal)
                    //     // })
                    //     if (jPortal.config.form.formConfirm){
                    //         var confirmTips = jPortal.config.form.confirmTips;
                    //         ElMessageBox.confirm(confirmTips, '提示', {
                    //             confirmButtonText: '确定',
                    //             cancelButtonText: '取消',
                    //             type: 'warning',
                    //         })
                    //         .then(() => {
                    //             ElMessage({
                    //                 type: 'success',
                    //                 message: '保存成功',
                    //             });
                    //         })
                    //         .catch(() => {

                    //         });
                    //         return;
                    //     } else {
                    //         ElMessage('Submit事件，请至控制台查看详情');
                    //     }
                    // },
                    submitBtn: false
                }
            },
            // 基础设置表单
            baseForm: {
                rule: field({ t }),
                api: {},
                options: {
                    form: {
                        labelPosition: 'top'
                    },
                    formCreateResetBtn: false,
                    submitBtn: false,
                    mounted: (fapi) => {
                        fapi.activeRule = data.activeRule;
                        fapi.setValue(fapi.options.formData || {});
                    }
                }
            },
            // 属性设置表单
            propsForm: {
                rule: [],
                api: {},
                options: {
                    form: {
                        labelPosition: 'top'
                    },
                    submitBtn: false,
                    mounted: (fapi) => {
                        fapi.activeRule = data.activeRule;
                        fapi.setValue(fapi.options.formData || {});
                    }
                }
            },
            // 验证设置表单
            validateForm: {
                rule: validate({ t }),
                api: {},
                options: {
                    form: {
                        labelPosition: 'top'
                    },
                    submitBtn: false,
                    mounted: (fapi) => {
                        fapi.activeRule = data.activeRule;
                        fapi.setValue(fapi.options.formData || {});
                    }
                }
            },
            // 系统变量
            Variables: [
                { label: '用户ID', value: 'SYS_USER_ID' },
                { label: '用户名称', value: 'SYS_USER_NAME' },
                { label: '用户账号', value: 'SYS_USER_ACCOUNT' },
                { label: '用户手机', value: 'SYS_USER_MOBILE' },
                { label: '部门ID', value: 'SYS_DEP_ID' },
                { label: '部门名称', value: 'SYS_DEP_NAME' },
                { label: '申请时间', value: 'SYS_APPLY_DATE' },
                { label: '申请单号', value: 'SYS_APPLY_NO' }
            ],
            // 系统常量
            Constant: {}
        });

        watch(
            () => data.preview.state,
            function (n) {
                if (!n) {
                    nextTick(() => {
                        data.preview.rule = data.preview.option = null;
                    });
                }
            }
        );

        watch(
            () => locale.value,
            () => {
                const formVal = data.form.api.formData && data.form.api.formData();
                const baseFormVal = data.baseForm.api.formData && data.baseForm.api.formData();
                const validateFormVal = data.validateForm.api.formData && data.validateForm.api.formData();
                data.validateForm.rule = validate({ t });
                data.baseForm.rule = field({ t });
                data.form.rule = form({ t });
                nextTick(() => {
                    formVal && data.form.api.setValue(formVal);
                    baseFormVal && data.baseForm.api.setValue(baseFormVal);
                    validateFormVal && data.validateForm.api.setValue(validateFormVal);
                });
            }
        );

        watch(
            () => props.forms,
            function (val) {
                if (props.forms.length > 0 && props.appInfo.formId == null) {
                    // 默认打开第一个Form
                    props.appInfo.formId = props.forms[0].id;
                }

                if (props.appInfo.formId != null) {
                    var formId = props.appInfo.formId;
                    var processItem = props.forms.find((item) => item.id == formId);
                    var command = methods.beforeCommand(processItem);
                    methods.changeForm(command);
                    data.processItem = processItem;
                }
                //app_classify 应用分类(0:表单应用 1:流程应用)
                var appType = props.appInfo.appClassify;
                if (appType == 0) {
                    data.form.value.form.formType = 3;
                    data.form.rule[0].children[1].children[0].props = { disabled: true };
                } else {
                    data.form.value.form.formType = 2;
                    data.form.rule[0].children[1].children[0].props = { disabled: false };
                }
            }
        );

        const methods = {
            // 模型绑定选择
            modelCheck(data, node, self) {
                const baseFormVal = self.baseForm.api.formData && self.baseForm.api.formData();
                var isChecked = node.checkedKeys.length != 0 ? true : false;
                if (isChecked) {
                    baseFormVal.field = data.field;
                    baseFormVal.table = data.table;
                    baseFormVal.isBind = true;
                    self.baseForm.api.setValue(baseFormVal);
                } else {
                    baseFormVal.table = '';
                    baseFormVal.isBind = false;
                }
                // 设置绑定状态
                self.baseForm.api.setValue(baseFormVal);
            },
            // 模型绑定选择(限制单选)
            modelCheckedChange(data, isChecked, self) {
                if (isChecked) {
                    const checked = [data.treeId];
                    self.$refs.tree.setCheckedKeys(checked);

                    const baseFormVal = self.baseForm.api.formData && self.baseForm.api.formData();
                    baseFormVal.field = data.field;
                    baseFormVal.isBind = true;
                    self.baseForm.api.setValue(baseFormVal);
                }
            },
            beforeCommand(command) {
                return {
                    self: this,
                    modelItem: command,
                    formItem: command
                };
            },
            changeModel(command) {
                var that = command.self;
                that.visible.layout = 'model';
                that.modelItem = command.modelItem;

                // 获取表单字段
                var formFields = '';
                var arrMatch = null;
                var rePattern = new RegExp(/"type":"(input|radio|datePicker|fc-editor)","field":"([\s\S]*?)","title":"([\s\S]*?)"/, 'gi');
                while ((arrMatch = rePattern.exec(methods.getJson()))) {
                    formFields += '{' + arrMatch[0] + '},';
                }

                var modelFields = props.modelTree.find((item) => item.id == that.modelItem.id);
                //var tableFields = that.modelItem.tableFields;
                var tableFields = modelFields.children;

                if (tableFields != null) {
                    //tableFields = JSON.parse(tableFields);
                    that.tableFields = tableFields.map((row) => {
                        //字符串 整形 日期时间 浮点 长整型 文本
                        var name = 'jd-input';

                        if (row.type == 'int' || row.type == 'bigint') {
                            name = 'jd-number';
                        }
                        if (row.type == 'text') {
                            name = 'jd-textarea';
                        }
                        if (row.type == 'datetime') {
                            name = 'jd-datePicker';
                        }

                        var ruleTitle = row.comment;
                        var field = row.field;
                        var table = row.table;

                        // 判断是否关联
                        var dataBind = false;
                        if (formFields != '' && formFields.indexOf('"field":"' + field + '"') > 0) {
                            dataBind = true;
                        }

                        // 数据模型列表
                        var rules = deepCopy(ruleList[name]);
                        rules.label = ruleTitle;
                        rules.name = name;
                        rules.field = field;
                        rules.table = table;
                        rules.dataBind = dataBind;

                        return rules;
                    });
                }
            },
            modelBind() {
                data.visible.layout = 'modelbind';
            },
            changeForm(command) {
                var that = command.self;
                that.processItem = command.formItem;

                if (that.processItem.formTemplate == null && that.processItem.formTemplate == '') {
                    return;
                }

                // 清空表单布局
                methods.clearDragRule();
                if (command.formItem == 'create') {
                    // 清空表单选项
                    that.processItem = null;

                    // 表单初始设置
                    data.form.value.form.formId = '';
                    data.form.value.form.formName = '';
                    data.form.value.form.labelWidth = '100px';
                    data.form.value.form.size = 'default';
                    data.form.value.form.labelPosition = 'right';

                    // 清空表单事件
                    data.form.value.mounted = eval('(function (){}())');
                    data.form.value.onReload = eval('(function (){}())');
                    data.form.value.onSubmit = eval('(function (){}())');

                    return;
                }

                // 获取表单布局
                var formTemplate = that.processItem.formTemplate;
                // 正则替换请求头
                var Header = `{"Authorization": "` + sysConfig.TOKEN_PREFIX + tool.cookie.get('TOKEN') + `"}`;
                formTemplate = formTemplate.replace(/{"Authorization":"([\s\S]*?)"}/g, Header);

                // 转成JSON对象
                formTemplate = JSON.parse(formTemplate);
                // 设置表单属性
                data.form.value = formTemplate.formOptions;
                data.form.value.form.formId = that.processItem.id;
                data.form.value.submitBtn.show = false;

                // 增加Parse函数
                formTemplate.formItems.forEach((item) => {
                    if (item.effect != null) {
                        if (item.effect.fetch && item.effect.fetch._parse) {
                            item.effect.fetch.parse = item.effect.fetch._parse;
                        }
                    }
                });

                // 增加表单事件
                formTemplate.formOptions.mounted = eval('(function (){return ' + formTemplate.formOptions.mounted + '}())');
                formTemplate.formOptions.onReload = eval('(function (){return ' + formTemplate.formOptions.onReload + '}())');
                formTemplate.formOptions.onSubmit = eval('(function (){return ' + formTemplate.formOptions.onSubmit + '}())');

                // 设置表单布局
                var formItems = JSON.stringify(formTemplate.formItems);
                methods.setRule(designerForm.parseJson(formItems));
            },
            async handleEvent(event) {
                if (!event.ctrlKey) return;
                switch (event.keyCode) {
                    case 67:
                        if (event.ctrlKey && event.code === 'KeyC') {
                            console.log('ctrl + c');
                        }
                        break;
                    case 83:
                        if (event.ctrlKey && event.code === 'KeyS') {
                            console.log('ctrl + s');
                            event.preventDefault();
                            event.returnValue = false; // 阻止直接保存网页
                            await methods.saveForm();
                        }
                        break;
                    case 86:
                        console.log('ctrl + v');
                        break;
                    case 89:
                        console.log('ctrl + y');
                        if (event.ctrlKey && event.code === 'KeyY') {
                            this.$router.go(+1);
                        }
                        break;
                    case 90:
                        break;
                }
            },
            openMenu(e) {
                this.$refs.contextmenu.openMenu(e);
            },
            handleCommand(command) {
                if (command == 'refresh') {
                    location.reload();
                }
                if (command == 'saveForm') {
                    methods.saveForm();
                }
                if (command == 'previewFc') {
                    methods.previewFc();
                }
                if (command == 'formConfig') {
                    methods.clearActiveRule();
                }
                if (command == 'formScript') {
                    data.visible.script = true;
                    data.visible.layout = 'modelbind';
                    nextTick(() => {
                        vm.refs.scriptDialog.open(data.form.value);
                    });
                }
            },
            async previewFc() {
                data.preview.state = true;
                data.preview.rule = methods.getRule();
                data.preview.option = methods.getOption();

                try {
                    var mountedJs = data.form.value.mounted.toString();
                    var defMountedJs = `
    // 注册事件脚本
    that.rule.forEach(item =>{
        if (item.on.length!=undefined){
            item.on = eval('(function (){return ' + item.on + '}())');
        }
    });`;
                    mountedJs = mountedJs.replace(/(SYS_USER_ID|SYS_USER_NAME|SYS_USER_ACCOUNT|SYS_USER_MOBILE|SYS_DEP_ID|SYS_DEP_NAME|SYS_APPLY_DATE|SYS_APPLY_NO)/gi, function (matchStr, p1) {
                        //console.log(`当前匹配到的子字符串：${p1}`)
                        // 将正则匹配到的子字符串作为索引key，返回对象字面量value(该value为要替换后的字符串)
                        return {
                            SYS_USER_ID: data.Constant.SYS_USER_ID,
                            SYS_USER_NAME: data.Constant.SYS_USER_NAME,
                            SYS_USER_ACCOUNT: data.Constant.SYS_USER_ACCOUNT,
                            SYS_USER_MOBILE: data.Constant.SYS_USER_MOBILE,
                            SYS_DEP_ID: data.Constant.SYS_DEP_ID,
                            SYS_DEP_NAME: data.Constant.SYS_DEP_NAME,
                            SYS_APPLY_DATE: data.Constant.SYS_APPLY_DATE,
                            SYS_APPLY_NO: data.Constant.SYS_APPLY_NO
                        }[p1];
                    });

                    //mountedJs = mountedJs.replace('function(jPortal){', 'function(jPortal){' + defMountedJs);
                    mountedJs = mountedJs.replace(/function(((^\s+)|(\s+$)|\s+)|)\(([\s\S]*)\)(((^\s+)|(\s+$)|\s+)|){/g, 'function(that){' + defMountedJs);

                    // 表单加载事件
                    data.preview.option.mounted = eval('(function (){return ' + mountedJs + '}())');
                    // 增加提交事件
                    //data.form.value.onSubmit = eval('(function (){alert(`AAAAA`)}())');

                    // data.preview.option.mounted = function(jPortal){
                    //     console.log('jPortal',jPortal)
                    //     jPortal.form.DHWB = new Date().getTime();

                    //     // 注册事件脚本
                    //     jPortal.rule.forEach(item =>{
                    //         if (item.on.length!=undefined){
                    //             item.on = eval('(function (){return ' + item.on + '}())');
                    //         }
                    //     });
                    // 字段列表
                    //jPortal.fields()
                    // 全部禁用
                    //jPortal.disabled(true)
                    // 全部隐藏
                    //jPortal.hidden(true);
                    //设置字段值
                    //jPortal.setValue({DHWB:'Hello'})

                    // 注册脚本事件：方法一
                    // jPortal.rule.find(item => item.field == 'XM').on = {
                    //     focus:(self)=>{
                    //         console.log("XXXX");
                    //         console.log(new Date().getTime())
                    //         console.log(jPortal.form.XM)
                    //     }
                    // };

                    // 注册脚本事件：方法二
                    //                     var defScript =
                    // `{
                    //     change:(self)=>{
                    //         console.log("XXXX");
                    //         console.log(new Date().getTime())
                    //         console.log(jPortal.form.XM)
                    //     }
                    // }
                    // `;
                    //                     jPortal.rule.find(item => item.field == 'XM').on = eval('(function (){return ' + defScript + '}())');
                    //};
                    // data.preview.option.onSubmit = function(formData, jPortal){
                    //     console.log('jPortal', formData);
                    //     //alert('AAAAAA')
                    // },
                    // data.form.value.onSubmit = function(formData, jPortal){
                    //     console.log('asdasd')
                    // },
                    //console.log('data.preview.option',data.preview.option)
                } catch (error) {
                    console.log(error);
                }
            },
            async saveForm() {
                // 保存表单配置
                var jsonForm = methods.getRule();
                var options = methods.getOption();

                // 判断元素为空
                if (data.dragForm.rule[0].children.length == 0) {
                    ElMessage.warning({
                        message: '空白表单不允许被保存，请拖入至少一个表单元素',
                        type: 'warning'
                    });
                    return;
                }

                var fromName = options.form.formName;
                if (fromName == '') {
                    methods.clearActiveRule();

                    ElMessageBox.prompt('请输入一个方便识别的表单名称', '温馨提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消'
                    }).then(({ value }) => {
                        // 设置表单名称
                        data.form.value.form.formName = value;
                        methods.saveForm();
                    });
                    return;
                }

                // 是否创建新表
                var isCreate = true;
                if (options.form.formId != '') {
                    isCreate = false;
                }
                // 获取拼音首字母
                PinYin.setOptions({ checkPolyphone: false, charCase: 0 });
                var firstLetter = PinYin.getCamelChars(fromName);
                var table = 'app_' + props.appInfo.appPackage + '_' + firstLetter.toLowerCase();

                // 获取表单字段
                var formFields = new Array();
                var jsonFields = JSON.parse(methods.getJson());
                jsonFields.forEach((item) => {
                    // 文字\间距\分割线\提示组件 不支持插入子组件元素
                    if (item.type == 'span' || item.type == 'div' || item.type == 'el-divider' || item.type == 'el-alert' || item.type == 'jd-link') return;

                    // 栅格\选项卡子项
                    if (item.type == 'FcRow' || item.type == 'el-tabs') {
                        item.children.forEach((item) => {
                            // 栅格中不存在组件
                            if (item.children == undefined) return;

                            var tableName = table;
                            if (item.table != null) {
                                tableName = item.table;

                                // 匹配到绑定数据，不允许创建新表
                                if (isCreate) isCreate = false;
                            }

                            var dataType = 'varchar';
                            var fieldType = item.children[0].type;
                            var field = item.children[0].field;
                            var fieldName = item.children[0].title;

                            if (fieldType == 'jd-number' || fieldType == 'inputNumber') {
                                dataType = 'int';
                            }
                            if (fieldType == 'input' || fieldType == 'radio') {
                                dataType = 'varchar';
                            }

                            // 表单字段
                            var fileItem = {
                                field: field,
                                fieldName: fieldName,
                                dataType: dataType,
                                table: tableName
                            };
                            formFields.push(fileItem);
                            if (field == '') {
                                ElMessage.warning({
                                    message: '表单中有字段为空值，请先设置字段ID再提交保存操作',
                                    type: 'warning'
                                });
                                return;
                            }
                        });
                        return;
                    }

                    // 正常布局字段
                    var tableName = table;
                    if (item.table != null) {
                        tableName = item.table;

                        // 匹配到绑定数据，不允许创建新表
                        if (isCreate) isCreate = false;
                    }

                    var dataType = 'varchar';
                    var fieldType = item.type;
                    var field = item.field;
                    var fieldName = item.title;

                    if (fieldType == 'jd-number' || fieldType == 'inputNumber') {
                        dataType = 'int';
                    }
                    if (fieldType == 'input' || fieldType == 'radio') {
                        dataType = 'varchar';
                    }

                    // 表单字段
                    var fileItem = {
                        field: field,
                        fieldName: fieldName,
                        dataType: dataType,
                        table: tableName
                    };
                    formFields.push(fileItem);
                    if (field == '') {
                        ElMessage.warning({
                            message: '表单中有字段为空值，请先设置字段ID再提交保存操作',
                            type: 'warning'
                        });
                        return;
                    }
                });

                // 获取字段个数
                var fieldNums = formFields.length;
                // 分组合并显示
                formFields = methods.dealTreeData(formFields);

                // 字段唯一性判断
                let maps = new Array();
                var mapsNums = 0;
                formFields.forEach((el) => {
                    el.fields.filter((fl) => {
                        if (maps[el.table + '_' + fl.field]) {
                            ElMessage.warning({
                                message: '表单中存在多个`[' + fl.fieldName + '(' + fl.field + ')]`，请更正后再提交保存操作',
                                type: 'warning'
                            });
                            return;
                        }
                        mapsNums++;
                        return maps[el.table + '_' + fl.field] ? false : (maps[el.table + '_' + fl.field] = true);
                    });
                });
                if (fieldNums != mapsNums) {
                    return;
                }

                // 模型自动创建
                if (isCreate) {
                    jsonForm.forEach((item) => {
                        if (item.type == 'FcRow' || item.type == 'el-tabs') {
                            if (item.children == undefined) return;
                            item.children.forEach((subItem) => {
                                subItem.children[0].isBind = true;
                                subItem.children[0].table = table;
                            });
                        } else {
                            item.isBind = true;
                            item.table = table;
                        }
                    });
                }

                var formTemplate = {
                    formOptions: options,
                    formItems: jsonForm,
                    formFields: formFields
                };

                var params = {
                    id: options.form.formId != null ? options.form.formId : '',
                    appId: props.appInfo.appCode,
                    appName: props.appInfo.appName,
                    formName: options.form.formName,
                    formType: options.form.formType,
                    formTemplate: tool.Stringify(formTemplate)
                };

                var res = {};
                if (params.id == '') {
                    res = await data.$API.app.form.addForm.post(params);
                } else {
                    res = await data.$API.app.form.updateForm.put(params);
                }

                if (res.code == 200) {
                    // 获取表单ID值
                    if (params.id == '') {
                        var formId = res.data;
                        data.form.value.form.formId = formId;
                    }

                    ElMessage.success({
                        message: '恭喜，保存成功',
                        type: 'success'
                    });
                } else {
                    ElMessage.warning({
                        message: res.msg,
                        type: 'warning'
                    });
                }
            },
            // JSON数据分组
            dealTreeData(data) {
                let map = {};
                var treeData = new Array();
                data.forEach((item, index) => {
                    //如果对象中不存在该组名 则放入treeData第一层
                    if (!map[item.table]) {
                        treeData.push({
                            table: item.table,
                            fields: [item]
                        });
                        map[item.table] = item;
                    } else {
                        treeData.forEach((child) => {
                            //属性相同 就放进同一组吧
                            if (child.table == item.table) {
                                child.fields.push(item);
                            }
                        });
                    }
                });
                return treeData;
            },
            // 保存表单脚本
            saveFormScript(flg, element, script) {
                data.visible.script = flg;
                switch (element) {
                    case 'onLoad':
                        data.form.value.mounted = eval('(function (){return ' + script + '}())');
                        break;
                    case 'onSubmit':
                        data.form.value.onSubmit = eval('(function (){return ' + script + '}())');
                        break;
                    default:
                        break;
                }
            },
            async formSetting(method) {
                if (method == 'formConfig') {
                    methods.clearActiveRule();
                }
                if (method == 'formScript') {
                    data.visible.script = true;
                    data.visible.layout = 'modelbind';
                    nextTick(() => {
                        vm.refs.scriptDialog.open(data.form.value);
                    });
                }
                if (method == 'formVariable') {
                    data.visible.variable = true;
                    nextTick(() => {
                        vm.refs.variableDialog.open();
                    });
                }
                if (method == 'delete') {
                    ElMessageBox.confirm('您确定要删除该表单？此操作不可被恢复。', '提示', {
                        confirmButtonText: '确定',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }).then(async () => {
                        var formId = data.form.value.form.formId;
                        var res = await API.app.form.del.delete(formId);
                        if (res.code == 200) {
                            // 清空布局表单
                            data.dragForm.rule[0].children = [];
                            // 清空选中元素
                            methods.clearActiveRule();
                            // 清空表单ID值
                            data.form.value.form.formName = '';
                            data.form.value.form.formId = '';
                            // 移除选中表单
                            data.processForms.splice(data.processItem, 1);
                            // 清空选择表单
                            data.processItem = null;

                            ElMessage.success({
                                message: '恭喜，删除成功',
                                type: 'success'
                            });
                        }
                    });
                }
            },
            makeChildren(children) {
                return reactive({ children }).children;
            },
            addMenu(config) {
                if (!config.name || !config.list) return;
                let flag = true;
                data.menuList.forEach((v, i) => {
                    if (v.name === config.name) {
                        data.menuList[i] = config;
                        flag = false;
                    }
                });
                if (flag) {
                    data.menuList.push(config);
                }
            },
            removeMenu(name) {
                [...data.menuList].forEach((v, i) => {
                    if (v.name === name) {
                        data.menuList.splice(i, 1);
                    }
                });
            },
            setMenuItem(name, list) {
                data.menuList.forEach((v) => {
                    if (v.name === name) {
                        v.list = list;
                    }
                });
            },
            appendMenuItem(name, item) {
                data.menuList.forEach((v) => {
                    if (v.name === name) {
                        v.list.push(item);
                    }
                });
            },
            removeMenuItem(item) {
                data.menuList.forEach((v) => {
                    let idx;
                    if (is.String(item)) {
                        [...v.list].forEach((menu, idx) => {
                            if (menu.name === item) {
                                v.list.splice(idx, 1);
                            }
                        });
                    } else {
                        if ((idx = v.list.indexOf(item)) > -1) {
                            v.list.splice(idx, 1);
                        }
                    }
                });
            },
            // 点击增加组件
            addDrag(item) {
                var ruleItem = methods.makeRule(item);

                // 从数据模型中取值
                if (item.field != null) {
                    var ruleChildren = deepCopy(ruleItem.children);
                    var ruleTitle = item.label;
                    var field = item.field;
                    var table = item.table;

                    ruleChildren[0].title = ruleTitle;
                    ruleChildren[0].field = field;
                    ruleChildren[0].table = table;
                    ruleChildren[0].isBind = true;

                    Object.assign(ruleItem.children, ruleChildren);
                }
                this.children.push(ruleItem);

                // 滚动到最底部
                this.$nextTick(() => {
                    let scrollEl = this.$refs.mianscroll;
                    scrollEl.scrollTo({ top: scrollEl.scrollHeight, behavior: 'smooth' });
                });
                //this.children.push(methods.makeRule(item));
            },
            addComponent(component) {
                if (Array.isArray(component)) {
                    component.forEach((v) => {
                        ruleList[v.name] = v;
                    });
                } else {
                    ruleList[component.name] = component;
                }
            },
            getParent(rule) {
                let parent = rule.__fc__.parent.rule;
                const config = parent.config;
                if (config && config.config.inside) {
                    rule = parent;
                    parent = parent.__fc__.parent.rule;
                }
                return { root: parent, parent: rule };
            },
            makeDrag(group, tag, children, on) {
                return {
                    type: 'DragBox',
                    wrap: {
                        show: false
                    },
                    col: {
                        show: false
                    },
                    inject: true,
                    props: {
                        rule: {
                            props: {
                                tag: 'el-col',
                                group: group === true ? 'default' : group,
                                ghostClass: 'ghost',
                                animation: 150,
                                handle: '._fc-drag-btn',
                                emptyInsertThreshold: 0,
                                direction: 'vertical',
                                itemKey: 'type'
                            }
                        },
                        tag
                    },
                    children,
                    on
                };
            },
            clearDragRule() {
                methods.setRule([]);
            },
            makeDragRule(children) {
                return methods.makeChildren([
                    methods.makeDrag(true, 'draggable', children, {
                        add: (inject, evt) => methods.dragAdd(children, evt),
                        end: (inject, evt) => methods.dragEnd(children, evt),
                        start: (inject, evt) => methods.dragStart(children, evt),
                        unchoose: (inject, evt) => methods.dragUnchoose(children, evt)
                    })
                ]);
            },
            async getConstant() {
                var res = await API.app.appStore.getVariable.get();
                if (res.code == 200) {
                    data.Constant = res.data;
                }
            },
            getRule() {
                return methods.parseRule(deepCopy(data.dragForm.api.rule[0].children));
            },
            getJson() {
                return designerForm.toJson(methods.getRule());
            },
            getOption() {
                const option = deepCopy(data.form.value);
                option.submitBtn = {
                    show: option.form.formCreateSubmitBtn,
                    innerText: t('form.submit')
                };
                option.resetBtn = {
                    show: option.form.formCreateResetBtn,
                    innerText: t('form.reset')
                };
                delete option.form.formCreateSubmitBtn;
                delete option.form.formCreateResetBtn;
                return option;
            },
            setRule(rules) {
                if (!rules) {
                    rules = [];
                }
                data.children = methods.makeChildren(methods.loadRule(is.String(rules) ? designerForm.parseJson(rules) : deepCopy(rules)));
                methods.clearActiveRule();
                data.dragForm.rule = methods.makeDragRule(data.children);
            },
            clearActiveRule() {
                data.activeRule = null;
                data.activeTab = 'form';
                data.visible.layout = 'control';
            },
            setOption(opt) {
                let option = { ...opt };
                option.form.formCreateSubmitBtn = !!option.submitBtn;
                option.form.formCreateResetBtn = !!option.resetBtn;
                option.submitBtn = false;
                delete option.resetBtn;
                data.form.value = option;
            },
            loadRule(rules) {
                const loadRule = [];
                rules.forEach((rule) => {
                    if (is.String(rule)) {
                        return loadRule.push(rule);
                    }
                    const config = ruleList[rule._fc_drag_tag] || ruleList[rule.type];
                    const _children = rule.children;
                    rule.children = [];
                    if (rule.control) {
                        rule._control = rule.control;
                        delete rule.control;
                    }
                    if (config) {
                        rule = methods.makeRule(config, rule);
                        if (_children) {
                            let children = rule.children[0].children;

                            if (config.drag) {
                                children = children[0].children;
                            }
                            children.push(...methods.loadRule(_children));
                        }
                    } else if (_children) {
                        rule.children = methods.loadRule(_children);
                    }
                    loadRule.push(rule);
                });
                return loadRule;
            },
            parseRule(children) {
                return [...children].reduce((initial, rule) => {
                    if (is.String(rule)) {
                        initial.push(rule);
                        return initial;
                    } else if (rule.type === 'DragBox') {
                        initial.push(...methods.parseRule(rule.children));
                        return initial;
                    } else if (rule.type === 'DragTool') {
                        rule = rule.children[0];
                        if (rule.type === 'DragBox') {
                            initial.push(...methods.parseRule(rule.children));
                            return initial;
                        }
                    }
                    if (!rule) return initial;
                    rule = { ...rule };
                    if (rule.children.length) {
                        rule.children = methods.parseRule(rule.children);
                    }

                    delete rule._id;
                    delete rule.key;
                    if (rule.config) {
                        delete rule.config.config;
                    }
                    if (rule.effect) {
                        delete rule.effect._fc;
                        delete rule.effect._fc_tool;
                    }
                    if (rule._control) {
                        rule.control = rule._control;
                        delete rule._control;
                    }
                    Object.keys(rule)
                        .filter((k) => (Array.isArray(rule[k]) && rule[k].length === 0) || (is.Object(rule[k]) && Object.keys(rule[k]).length === 0))
                        .forEach((k) => {
                            delete rule[k];
                        });
                    initial.push(rule);
                    return initial;
                }, []);
            },
            baseChange(field, value, _, fapi) {
                if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
                    data.activeRule[field] = value;
                    data.activeRule.config.config?.watch?.['$' + field]?.({
                        field,
                        value,
                        api: fapi,
                        rule: data.activeRule
                    });
                }
            },
            propRemoveField(field, _, fapi) {
                if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
                    const org = field;
                    data.dragForm.api.sync(data.activeRule);
                    if (field.indexOf('formCreate') === 0) {
                        field = field.replace('formCreate', '');
                        if (!field) return;
                        field = lower(field);
                        if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
                            delete data.activeRule.effect[field.split('>')[1]];
                        } else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
                            delete data.activeRule.props[field.split('>')[1]];
                        } else if (field === 'child') {
                            delete data.activeRule.children[0];
                        } else if (field) {
                            data.activeRule[field] = undefined;
                        }
                    } else {
                        delete data.activeRule.props[field];
                    }
                    data.activeRule.config.config?.watch?.[org]?.({
                        field: org,
                        value: undefined,
                        api: fapi,
                        rule: data.activeRule
                    });
                }
            },
            propChange(field, value, _, fapi) {
                if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
                    const org = field;
                    if (field.indexOf('formCreate') === 0) {
                        field = field.replace('formCreate', '');
                        if (!field) return;
                        field = lower(field);
                        if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
                            data.activeRule.effect[field.split('>')[1]] = value;
                        } else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
                            data.activeRule.props[field.split('>')[1]] = value;
                        } else if (field === 'child') {
                            data.activeRule.children[0] = value;
                        } else {
                            data.activeRule[field] = value;
                        }
                    } else if (field.indexOf('formTable') === 0) {
                        if (!field) return;
                        // const addTemplate = {};
                        // const propMapLabel = {};
                        // for (let i = 0; i < value.length; i++) {
                        //     const prop = value[i].tableColumn;
                        //     if (prop) {
                        //         addTemplate[prop.prop] = '';
                        //         propMapLabel[prop.prop] = prop.label;
                        //     }
                        // }
                        // data.activeRule.props.addTemplate = addTemplate;
                        // data.activeRule.props.propMapLabel = propMapLabel;
                        const childrenList = [];
                        const addTemplate = {};
                        for (let i = 0; i < value.length; i++) {
                            if (value[i].tableColumn) {
                                childrenList.push(deepCopy(value[i].tableColumn));
                                addTemplate[value[i].tableColumn.props.prop] = '';
                            }
                        }
                        // const v = value.filter((item) => {
                        //     return item.tableColumn;
                        // });

                        data.activeRule.props.addTemplate = addTemplate;
                        data.activeRule.children = childrenList;
                        data.activeRule.formTableAddTemplate = value;
                        data.activeRule.props[field] = value;
                    } else {
                        data.activeRule.props[field] = value;
                    }
                    data.activeRule.config.config?.watch?.[org]?.({
                        field: org,
                        value,
                        api: fapi,
                        rule: data.activeRule
                    });
                }
            },
            validateChange(formData) {
                if (!data.activeRule || data.validateForm.api[data.activeRule._id] !== data.activeRule) return;
                data.activeRule.validate = formData.validate || [];
                data.dragForm.api.refreshValidate();
                data.dragForm.api.nextTick(() => {
                    data.dragForm.api.clearValidateState(data.activeRule.field);
                });
            },
            toolActive(rule) {
                if (data.activeRule) {
                    delete data.propsForm.api[data.activeRule._id];
                    delete data.baseForm.api[data.activeRule._id];
                    delete data.validateForm.api[data.activeRule._id];
                    delete data.dragForm.api.activeRule;
                }
                data.activeRule = rule;
                data.dragForm.api.activeRule = rule;

                nextTick(() => {
                    data.activeTab = 'props';
                    nextTick(() => {
                        data.propsForm.api[data.activeRule._id] = data.activeRule;
                        data.baseForm.api[data.activeRule._id] = data.activeRule;
                        data.validateForm.api[data.activeRule._id] = data.activeRule;
                    });
                });

                if (!data.cacheProps[rule._id]) {
                    data.cacheProps[rule._id] = rule.config.config.props(rule, { t, api: data.dragForm.api });
                }

                data.propsForm.rule = data.cacheProps[rule._id];

                const formData = { ...rule.props, formCreateChild: rule.children[0] };
                Object.keys(rule).forEach((k) => {
                    if (['effect', 'config', 'payload', 'id', 'type'].indexOf(k) < 0) formData['formCreate' + upper(k)] = rule[k];
                });
                ['props', 'effect'].forEach((name) => {
                    rule[name] &&
                        Object.keys(rule[name]).forEach((k) => {
                            formData['formCreate' + upper(name) + '>' + k] = rule[name][k];
                        });
                });
                data.propsForm.options.formData = formData;

                data.showBaseRule = hasProperty(rule, 'field') && rule.input !== false && (!config.value || config.value.showBaseForm !== false);
                data.showValidate = hasProperty(rule, 'field') && rule.validate !== false && (!config.value || config.value.showBaseForm !== false);

                if (data.showBaseRule) {
                    data.baseForm.options.formData = {
                        field: rule.field,
                        title: rule.title || '',
                        table: rule.table || '',
                        isBind: rule.isBind || false,
                        placeholder: rule.placeholder || '',
                        info: rule.info,
                        _control: rule._control
                    };
                    data.validateForm.options.formData = { validate: rule.validate ? [...rule.validate] : [] };
                }
            },
            dragStart(children) {
                data.moveRule = children;
                data.added = false;
            },
            dragUnchoose(children, evt) {
                data.addRule = {
                    children,
                    oldIndex: evt.oldIndex
                };
            },
            dragAdd(children, evt) {
                const newIndex = evt.newIndex;
                const menu = evt.item._underlying_vm_;
                if (!menu || menu.__fc__) {
                    // 点击激活组件
                    if (data.addRule) {
                        const rule = data.addRule.children.splice(data.addRule.oldIndex, 1);
                        children.splice(newIndex, 0, rule[0]);
                    }
                } else {
                    // 拖拽加入组件
                    const rule = methods.makeRule(ruleList[menu.name]);

                    // 获取模型数据
                    var element = evt.item.__draggable_context.element;
                    if (element.field != null) {
                        var ruleChildren = deepCopy(rule.children);

                        var ruleTitle = element.label;
                        var field = element.field;
                        var table = element.table;

                        ruleChildren[0].title = ruleTitle;
                        ruleChildren[0].field = field;
                        ruleChildren[0].table = table;
                        ruleChildren[0].isBind = true;

                        Object.assign(rule.children, ruleChildren);
                    }
                    children.splice(newIndex, 0, rule);
                }
                data.added = true;
                // data.dragForm.api.refresh();
            },
            dragEnd(children, { newIndex, oldIndex }) {
                if (!data.added && !(data.moveRule === children && newIndex === oldIndex)) {
                    const rule = data.moveRule.splice(oldIndex, 1);
                    children.splice(newIndex, 0, rule[0]);
                }
                data.moveRule = null;
                data.addRule = null;
                data.added = false;
                // data.dragForm.api.refresh();
            },
            makeRule(config, _rule) {
                const rule = _rule || config.rule({ t });
                rule.config = { config };
                if (!rule.effect) rule.effect = {};
                rule.effect._fc = true;
                rule._fc_drag_tag = config.name;

                let drag;

                if (config.drag) {
                    rule.children.push(
                        (drag = methods.makeDrag(config.drag, rule.type, methods.makeChildren([]), {
                            end: (inject, evt) => methods.dragEnd(inject.self.children, evt),
                            add: (inject, evt) => methods.dragAdd(inject.self.children, evt),
                            start: (inject, evt) => methods.dragStart(inject.self.children, evt),
                            unchoose: (inject, evt) => methods.dragUnchoose(inject.self.children, evt)
                        }))
                    );
                }

                if (config.children && !_rule) {
                    const child = methods.makeRule(ruleList[config.children]);
                    (drag || rule).children.push(child);
                }

                const dragMask = mask.value !== undefined ? mask.value !== false : config.mask !== false;

                if (config.inside) {
                    rule.children = methods.makeChildren([
                        {
                            type: 'DragTool',
                            props: {
                                dragId: config,
                                dragBtn: config.dragBtn !== false,
                                children: config.children,
                                mask: dragMask,
                                converts: convertList
                            },
                            effect: {
                                _fc_tool: true
                            },
                            inject: true,
                            on: {
                                delete: ({ self }) => {
                                    const parent = methods.getParent(self).parent;
                                    parent.__fc__.rm();
                                    vm.emit('delete', parent);
                                    methods.clearActiveRule();
                                },
                                create: ({ self }) => {
                                    const top = methods.getParent(self);
                                    vm.emit('create', top.parent);
                                    top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(top.parent.config.config));
                                },
                                addChild: ({ self }) => {
                                    const top = methods.getParent(self);
                                    const config = top.parent.config.config;
                                    const item = ruleList[config.children];
                                    if (!item) return;
                                    (!config.drag ? top.parent : top.parent.children[0]).children[0].children.push(methods.makeRule(item));
                                },
                                copy: ({ self }) => {
                                    const top = methods.getParent(self);
                                    vm.emit('copy', top.parent);
                                    top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent));
                                },
                                active: ({ self }) => {
                                    const top = methods.getParent(self);
                                    vm.emit('active', top.parent);
                                    methods.toolActive(top.parent);
                                }
                            },
                            children: rule.children
                        }
                    ]);
                    return rule;
                } else {
                    return {
                        type: 'DragTool',
                        props: {
                            rule: rule,
                            dragId: config,
                            dragBtn: config.dragBtn !== false,
                            children: config.children,
                            mask: dragMask,
                            converts: convertList
                        },
                        effect: {
                            _fc_tool: true
                        },
                        inject: true,
                        on: {
                            // 模型字段关联
                            binding: ({ self }) => {
                                vm.emit('active', self.children[0]);
                                methods.toolActive(self.children[0]);

                                // 模型绑定字段
                                var table = self.children[0].table;
                                var field = self.children[0].field;
                                if (table != undefined) {
                                    data.modelId = [table + '@' + field];
                                } else {
                                    // 清除模型树选择值
                                    nextTick(() => {
                                        vm.refs.tree.setCheckedKeys([]);
                                    });
                                }

                                // 切换到模型树结构
                                methods.modelBind();
                            },
                            // 切换控件类型
                            convert: ({ self }, newItem) => {
                                // 原始控件
                                var originalItem = self.children[0];

                                vm.emit('create', self.children[0]);
                                const top = methods.getParent(self);

                                // 切换控件
                                var itemRule = methods.makeRule(newItem);
                                itemRule.children[0].field = originalItem.field;
                                itemRule.children[0].title = originalItem.title;

                                // 创建新控件
                                top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, itemRule);
                                // 删除原始控件
                                vm.emit('delete', self.children[0]);
                                self.__fc__.rm();
                            },
                            delete: ({ self }) => {
                                vm.emit('delete', self.children[0]);
                                self.__fc__.rm();
                                methods.clearActiveRule();
                            },
                            create: ({ self }) => {
                                vm.emit('create', self.children[0]);
                                const top = methods.getParent(self);
                                top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(self.children[0].config.config));
                            },
                            addChild: ({ self }) => {
                                const config = self.children[0].config.config;
                                const item = ruleList[config.children];
                                if (!item) return;
                                (!config.drag ? self : self.children[0]).children[0].children.push(methods.makeRule(item));
                            },
                            copy: ({ self }) => {
                                vm.emit('copy', self.children[0]);
                                const top = methods.getParent(self);
                                top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent));
                            },
                            active: ({ self }) => {
                                vm.emit('active', self.children[0]);
                                methods.toolActive(self.children[0]);

                                if (data.visible.layout == 'modelbind') {
                                    // 模型绑定字段
                                    var table = self.children[0].table;
                                    var field = self.children[0].field;

                                    if (table != undefined) {
                                        data.modelId = [table + '@' + field];
                                    } else {
                                        nextTick(() => {
                                            vm.refs.tree.setCheckedKeys([]);
                                        });
                                    }
                                }
                            }
                        },
                        children: methods.makeChildren([rule])
                    };
                }
            }
        };
        data.dragForm.rule = methods.makeDragRule(methods.makeChildren(data.children));
        return {
            ...toRefs(data),
            ...methods,
            dragHeight,
            t
        };
    },
    created() {
        document.body.ondrop = (e) => {
            e.preventDefault();
            e.stopPropagation();
        };
        // 获取系统常量
        this.getConstant();
    },
    mounted() {
        var that = this;
        window.addEventListener('keydown', that.handleEvent);
    },
    beforeDestroy() {
        // 在页面销毁的时候记得解除
        window.removeEventListener('keydown', that.handleEvent);
    }
});
</script>
<style lang="scss">
._fc-designer {
    height: 100%;
    min-height: 500px;
    overflow: hidden;
    cursor: default;
    position: relative;
}

._fc-designer > .el-main {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 0px;
}

._fc-m .form-create ._fc-l-item {
    background: #2e73ff;
    width: 100%;
    height: 10px;
    overflow: hidden;
    transition: all 0.3s ease;
}

._fc-l,
._fc-m,
._fc-r {
    border-top: 1px solid #ececec;
    box-sizing: border-box;
}

._fc-l-group {
    padding: 0 12px;
}

._fc-l-title {
    font-size: 13px;
    height: 35px;
    line-height: 35px;
    color: #999999;
}

._fc-l-content {
    border-top: solid 1px #e4e7ed;
    border-left: solid 1px #e4e7ed;
}

._fc-l-item {
    position: relative;
    display: inline-block;
    background: #fff;
    color: #000;
    min-width: 70px;
    width: 33.33%;
    height: 80px;
    line-height: 1;
    text-align: center;
    transition: all 0.2s ease;
    cursor: pointer;
    border-right: solid 1px #e4e7ed;
    border-bottom: solid 1px #e4e7ed;
}

._fc-l-item.sortable-chosen.ghost {
    width: 100%;
    border: 1px dashed #9e9d9d;
}

._fc-l-item i {
    font-size: 24px;
    display: inline-block;
}

._fc-l-item ._fc-l-name {
    font-size: 13px;
    display: block;
}
._fc-l-item ._fc-l-remark {
    color: #aaaaaa;
    margin-top: 3px;
    display: block;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
}

._fc-l-item ._fc-l-icon {
    padding: 12px 5px 10px;
}

._fc-l-item:hover {
    background: #2e73ff;
    color: #fff;
}

._fc-l-item .dataBind {
    position: absolute;
    right: 5px;
    top: 5px;
    z-index: 999;
}

._fc-m-tools {
    height: 40px;
    align-items: center;
    display: flex;
    justify-content: flex-end;
    border: 1px solid #ececec;
    border-top: 0 none;
}

._fc-m-tools button.el-button {
    padding: 5px 14px;
    display: flex;
    align-items: center;
}

._fc-m-tools .fc-icon {
    font-size: 14px;
    margin-right: 2px;
}

._fc-r .el-tabs__nav-wrap::after {
    height: 1px;
    background-color: #ececec;
}

._fc-r ._fc-r-tabs {
    display: flex;
    padding: 0;
    border-bottom: 1px solid #ececec;
}

._fc-r ._fc-r-tab {
    height: 40px;
    box-sizing: border-box;
    line-height: 40px;
    display: inline-block;
    list-style: none;
    font-size: 15px;
    font-weight: 600;
    color: #303133;
    position: relative;
    flex: 1;
    text-align: center;
    cursor: pointer;
}

._fc-r ._fc-r-tab.active {
    color: #409eff;
    border-bottom: 2px solid #409eff;
}

._fc-r ._fc_card {
    border: none;
    background: #fff;
}
._fc-r ._fc_card .el-card__body {
    padding-bottom: 0px !important;
}

.drag-box {
    min-height: 50px;
    width: 100%;
}

._fc-m-drag {
    overflow: auto;
    padding: 2px;
    box-sizing: border-box;
    position: relative;
}

._fc-m-drag_wap_header {
    margin: 0px auto;
    width: 375px;
    height: 60px;
    top: 0px;
    background: url('~@/assets/imgs/design_wap_header.png') #fff no-repeat !important;
    border-bottom: solid 1px #c0c0c0;
}

._fc-m-drag_wap {
    margin: 0px auto;
    width: 375px;
    height: calc(100% - 130px) !important;
    background: url('~@/assets/imgs/design_wap_bg.png') repeat-y !important;
    padding: 15px;
}

._fc-m-drag_wap_footer {
    margin: 0px auto;
    width: 375px;
    height: 70px;
    background: url('~@/assets/imgs/design_wap_footer.png') #fff no-repeat !important;
    border-top: solid 1px #c0c0c0;
}

._fc-m-drag,
.draggable-drag {
    background: #fff;
    height: 100%;
    position: relative;
}

._fc-m-drag .empty {
    position: absolute;
    top: 200px;
    margin: 0px 15%;
    width: 65%;
    overflow: hidden;
    height: 300px;
}

._fc-m-drag > form,
._fc-m-drag > form > .el-row {
    height: 100%;
}
.el-select .el-input__wrapper {
    width: 260px;
}
.el-form-item {
    padding-top: 10px;
    padding-bottom: 10px;
    margin: 0px;
}
.model_wrap .is-disabled {
    display: none;
}
.el-form-item__content {
    line-height: 20px !important;
}
</style>
